Cart flow

  • Code

    1. Adding button in View

    
                       <a href="javascript:void(0);" class="add_to_cart" data-id="{$val->id}" data-type="cart"> 
                            <div class="col-12">
                              ADD CARD
                          </div>
                        </a>
    
                        <a href="javascript:void(0);" class="add_to_cart" data-id="{$val->id}"> 
                          <div class="col-12">
                              BUY NOW
                          </div>
                      </a>
    

    2. Add to cookie in javascript

    Please note that why we use cookie here. User will add more than one product to the cart. The user added product should be available when the user navigate to other pages in the website. So we need to save the products which user added to the cart in somewhere (cookie or session or database)

    1. when click on the 'add to cart' button, 'add_to_cart' referece of button will be trigger the given funtion

    2. in the function we use cookie variable 'cart_item'. It contains json string data (multiple products)

    3. the function 'JSON.parse()' is used to convert the json string to array object

    4. then function 'findIndex()' is used to check the user selected product exists in the cart or not

    5. if exists, increase the quantity of the product

    6. if not exists, add new object of the product to the array using 'push()'

    7. again convert the array object to json string to save in the cookie using 'JSON.stringify()'

    
                       $(document).on('click', '.add_to_cart', function () {
          
    
          var item_id=$(this).attr('data-id');
          var data_type=$(this).attr('data-type');
              
          var title=$(this).parent().parent().parent().find('.data-title').text(); 
          var price=$(this).parent().parent().parent().find('.data-price').text(); 
              
    
          var cartItem=[];
          var cartItemTotal=0;
          if ($.cookie('cart_item')) { 
               cartItem=JSON.parse($.cookie("cart_item"));
          }    
          
          indexOfObject = cartItem.findIndex((obj => obj.item_id == item_id)); 
          if(indexOfObject>=0){
              var total= (cartItem[indexOfObject].quantity+1)*cartItem[indexOfObject].price
              cartItem[indexOfObject].quantity = cartItem[indexOfObject].quantity+1;
              cartItem[indexOfObject].total = total;
          }
          else{
              cartItem.push({'item_id':item_id, 'price':price, 'quantity':1, 'title':title});
          }     
        
          
          cartItemTotal=cartItem.length;
          $('.cart_item_total').text(cartItemTotal);
          
          
          $.cookie("cart_item",JSON.stringify(cartItem), { path: '/' });      
          $.toast({ 
              text : "Successfully added to your cart", 
              showHideTransition : 'fade',  // It can be plain, fade or slide
              bgColor : 'green',              // Background color for toast
              textColor : '#eee',            // text color
              allowToastClose : false,       // Show the close button or not
              hideAfter : 5000,              // `false` to make it sticky or time in miliseconds to hide after
              stack : 5,                     // `fakse` to show one stack at a time count showing the number of toasts that can be shown at once
              textAlign : 'left',            // Alignment of text i.e. left, right, center
              position : 'top-right'       // bottom-left or bottom-right or bottom-center or top-left or top-right or top-center or mid-center or an object representing the left, right, top, bottom values to position the toast on page
          });
    
          if(data_type=='buynow'){
              window.location.href=CART_URL;
          }
      });
                        

    3. show all cart items in a page

    route
    
                        Route::get('/cart', [OrderController::class, 'cart'])->name('cart');
                        
    in controller
    
       public function cart(Request $r)
        {    
            $cartItems=json_decode($_COOKIE['cart_item'],1);
            $this->data['cartItem']=[];
            $cartTotal=0;
            foreach($cartItems as $row){
                $product=Product::join('pages','pages.id','=','products.page_id')
                                    ->select('pages.title','pages.slug_url','pages.image','pages.content','products.*')
                                    ->where('products.id', $row['item_id'])->first()->toArray();
    
                $price=$this->data['VISITOR_IP_COUNTRY']=='INR' ?  $product['price_inr'] : $product['price_usd'];                  
                $this->data['cartItem'][]= [
                        'item_id'=>$product['id'],
                        'title'=>$product['title'],
                        'price'=>$price,
                        'currency'=>$this->data['VISITOR_IP_COUNTRY']=='INR' ? '₹' :'$',
                        'image'=>$product['image'],
                        'delivery_info'=>$product['delivery_info'],
                        'delivery_days'=>$product['delivery_days'],
                        'quantity'=>$row['quantity']
                ];
    
                $cartTotal=$cartTotal+($price*$row['quantity']);
            }  
            
            $this->data['cartTotal']=$cartTotal;
            if(Session::get('user')){
                $this->data['user']=Session::get('user');
            } 
            if(Auth::id()){            
                $this->data['delivery_address']=Address::where('user_id', Auth::id())->where('default_delivery','1')->first();
            }         
            return view('fe.cart',$this->data);
    }
    
      
    View

    1. check user is logged in or not

    2. if logged in, need 'delivery_id' hidden field

    3. if logged in, show current delivery address

    4. if not logged in, show sign in button for loggin

    
    ?php   
    if(isset($user) && $user->id>0){
    ?>
                          <input type="hidden" id="delivery_id" name="delivery_id" value="{isset($delivery_address->id) ? $delivery_address->id : 0}">
                          {$delivery_address->firstname} {$delivery_address->lastname}, 
                          {$delivery_address->address},
                          {$delivery_address->city},
                          {$delivery_address->state},
                          {$delivery_address->country}-{$delivery_address->pin}<br>
                          Lankmark : {$delivery_address->landmark},<br>
                          Mobile: {$delivery_address->mobile}
    ?php
    }
    else{
    ?>
    <a href="javascript:void(0);goToPage('Customer','login','cart')" class="change-btn">Sign in</a>
    ?php
    }
    ?>
    

    5. show cart items

    
    ?php if(isset($cartItem)){
                    
                    foreach($cartItem as $iRow){ ?>
                          <div class="row">
                             <div class="col-lg-2 col-md-4 col-sm-4 col-2 item-img text-center">
                                  <img src="{asset('public/uploads/pages/'.$iRow['image'])}" class="img-fluid">
                          </div> 
                          <div class="col-lg-6 col-md-6 col-sm-8 col-10  item-name ppd-20"> 
                          <b>{$iRow['title']}</b> 
                          <div class="cart-offer">  
                         
                          <b>{$iRow['currency']}{$iRow['price']}</b>
                         
                          </div>
                          </div>
    
                          <div class="col-lg-4 col-md-12 col-sm-12 item-delivery ppd-20">
                          <span class="mb-05-cu d-block">Delivery by {$iRow['delivery_days']}</span>
                          <span class="replacement">{$iRow['delivery_info']}</span>
                          </div>
                          <div class="col-lg-12 col-md-12 col-sm-12 actions-main ppd-20 p-t-0">
                          <span class="cart_minus" data-id="{$iRow['item_id']}">-</span>
                          <input type="text" class="cart-count" value="{$iRow['quantity']}" readOnly>
                          <span class="cart_plus" data-id="{$iRow['item_id']}">+</span>
                          
                          <a href="javascript:void(0);" data-id="{$iRow['item_id']}" class="remove_cart"> REMOVE</a>
                          </div>
                          </div>
    
    
                  ?php }} ?>
    
                    

    7. show cart summary

    
    
                    <form id="frm_checkout" action="#" method="post">
              <input type="hidden" name="_token" value="J0fXaHIURHuLjCwGJ7sma6dP9moPLm3gHJaQTIPv">          <div class="col-lg-12 col-md-12 col-sm-12 ppd-20 price-top ">
                  <b> PRICE DETAILS  </b>
                </div>
                <div class="col-lg-12 col-md-12 col-sm-12 price-detail ppd-20 p-b-0 d-flex justify-content-between ">
                  <p>Price (<span class="cart_item_total">{count($cartItem)}</span> items)  </p>
                  <p class="text-end">₹<span class="cartSubTotalAmount">{$cartTotal}</span> </p>
                </div>
                <!-- <div class="col-lg-12 col-md-12 col-sm-12 price-detail ppd-20 p-b-0 d-flex justify-content-between ">
                  <p class="text-success">Discount </p>
                  <p class="text-end text-success">− ₹2,645 </p>
                </div> -->
                <div class="col-lg-12 col-md-12 col-sm-12 price-detail ppd-20 d-flex justify-content-between ">
                  <p class="text-success">Delivery Charges </p>
                  <p class="text-end text-success">FREE </p>
                </div>
                <div class="col-lg-11 mx-auto price-line"></div>
                <div class="col-lg-12 col-md-12 col-sm-12 price-detail ppd-20 d-flex justify-content-between ">
                  <b>Total Amount </b>
                  <b class="text-end">₹<span class="cartGrandTotalAmount">{$cartTotal}</span></b>
                </div>
                <div class="col-lg-11 mx-auto price-line"></div>
                <div class="col-lg-12 col-md-12 col-sm-12 price-detail ppd-20 d-flex justify-content-between ">
                  <button type="button" class="btn btn-primary place_order">PLACE ORDER</button>
                </div>
                </form>
    
                    

    Payment integration when click on 'PLACE ORDER' button

    1. need razorpay.com library checkout.js

    2. 'place_order' reference call the place_order route using ajax

    3. function 'doPyament()' is used for openning the razor payment window. It is called in the success of ajax call (place_order)

    4. after the payment, we need to verify the payment using verifyPayment(). inside the verifyPayment(), we use ajax call and pass razorpay_payment_id which we got from razor pay

    
    
     
    
    <script src="https://checkout.razorpay.com/v1/checkout.js"></script>
      <script> 
      var PAYMENT_SUCCESS_URL="payment-response";
      var DASHBOARD_URL="order";
      var show_cart_item=1;
      var RAZOR_KEY="{ env('RAZOR_KEY_ID') }";
      var USER_ID="{isset($user) ? $user->id : '' }";
      var USER_MOBILE="{isset($user) ? $user->mobile : '' }";
      var USER_EMAIL="{isset($user) ? $user->email : ''}";
    
    
      var currency='USD';
      ?php
      if($VISITOR_IP_COUNTRY=='IN'){
        ?>
        currency='INR';
        <php
      }
      ?>
    
    
    $('.place_order').click(function(){
              if(USER_ID>0){
                        $('.place_order').prop('disabled', true);
                        var delivery_id=$('#delivery_id').val();
                        //alert(delivery_id);
                        var grand_total=$('.cartGrandTotalAmount').text();
                        var sub_total=$('.cartSubTotalAmount').text();
                        var error=0;
                        var message='';
                        if(delivery_id=='0'){
                          error=1;
                          message="Please select a delivery address.";
                        }
                        if(grand_total==''){
                          error=1;
                          message="Please add item to the cart.";
                        }
    
                        if(error==0){
    
                                $.ajax({
                                  type: 'POST',
                                  url: PLACE_ORDER_URL,
                                  headers: {
                                    'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                                  },
                                  data:{       
                                    'items' :$.cookie("cart_item"),
                                    'delivery_id':delivery_id,
                                    'grand_total':grand_total,
                                    'sub_total' :sub_total
            
                                  },
                      
                                  dataType: 'json',
                                  success:function(data){	     
                                    
                                    
                                        if(currency=='INR'){                                 
                                            doPyament(data.order_id);
                                        }  
                                        else{  
                                            doPaypalPayment(data.request_id);
                                        }
    
    
                                    
                                  },
                                  error: function(xhr, ajaxOptions, thrownError) { // if error occured
                                      response =jQuery.parseJSON(xhr.responseText);											
                                      error_message(response.text);
                                        
                                  }	
                      
                                });
    
                        } 
                        else{
                          error_message(message);
                        }
    
              }
              else{
                 $.cookie("redirect_url",CART_URL);   
                 window.location.href=LOGIN_URL;
              }
              
        });
    
        function doPyament(order_id){
    
               var totalAmount = CartTotal;
               var currency='INR';
               if(currency=='INR'){
                  totalAmount=totalAmount*100;
               }
               else{
                  totalAmount=totalAmount*100;
               }
               
               var options = {
               "key": RAZOR_KEY,
               "id" : order_id,
               "receipt" :order_id ,
               "payment_capture" :1,
               "amount": Math.round(totalAmount), // 2000 paise = INR 20
               "currency" :currency,
               "name": "Brown Paper Craft",
               "description": "Payment",
               "image": "http://organicplanters.in/public/fe/images/logo.png",
               "handler": function (response){                
                    verifyPayment(order_id, response.razorpay_payment_id);
              },
              "prefill": {
                   "contact": USER_MOBILE,
                   "email":   USER_EMAIL,
               },
               "theme": {
                   "color": "#528FF0"
               },
               "modal": {
                      "ondismiss": function(){
                           //window.location.href = PAYMENT_CANCEL_URL;
                          
                      }
                }
             };
             var rzp1 = new Razorpay(options);
             rzp1.open();
    
    
        }
    
        function verifyPayment(order_id, razorpay_payment_id){
                $.ajax({
                  type: "POST",
                  url: PAYMENT_SUCCESS_URL,
                  data: "order_id="+order_id+"&razorpay_payment_id=" + razorpay_payment_id,
                  headers: {
                      'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                  },
                  success: function (output) {
                    if(output.status=="success")
                    {
                          Swal.fire({
                                title: 'Success !!',
                                text: 'Successfully added fund to the wallet.',
                                icon: 'success',
                                confirmButtonText: 'Ok'
                                }).then((result) => {
                                      window.location.href = DASHBOARD_URL;
                          })
                    }
                    else{
                          Swal.fire({
                                title: 'Error !!',
                                text: 'Something went wrong if any amount is deducted it will refund with in 10-14 days',
                                icon: 'error',
                                confirmButtonText: 'Ok'
                                })
                    }
    
                  },
                  error: function (error) {
                    Swal.fire({
                                title: 'Error !!',
                                text: 'Something went wrong if any amount is deducted it will refund with in 10-14 days',
                                icon: 'error',
                                confirmButtonText: 'Ok'
                                })
                  }
              });
        }
    
        function doPaypalPayment(order_id){
          window.location="https://blog.manvia.in/paypal-payment?order_id="+order_id;
        }
    
        

    Route and Functions called in the javascript when placing the order

    placeOrder function

    1. save the cart item into OrderRequest & OrderRequestItems for developer purpose

    2. return order->id to the ajax response

    
        public function placeOrder(Request $request)
        {
    
            $input=$request->all();
    
            $input['discount_amount']=isset($input['discount_amount']) ? $input['discount_amount'] : 0;
            $input['tax_amount']=isset($input['tax_amount']) ? $input['tax_amount'] : 0;
            $input['delivery_charge']=isset($input['delivery_charge']) ? $input['delivery_charge'] : 0;
    
            $order=OrderRequest::create([
                'created_by' =>Auth::id(),
                'delivery_id'=>$input['delivery_id'],
                'payment_status'=>'Initiated',
                'order_date'=>date("Y-m-d H:i:s") ,
                'sub_total'=> $input['sub_total'],
                'discount_amount'=> $input['discount_amount'],
                'tax_amount'=> $input['tax_amount'],
                'delivery_charge'=> $input['delivery_charge'],
                'grand_total'=> $input['grand_total']       
            ]);
    
    
            $items=json_decode($input['items'],1);
            if(isset($items)){
                $amount=[];
                foreach($items as $row){ 
                    OrderRequestItems::create(
                            [
                                'order_request_id'=>$request->id,
                                'product_id'=>$row['item_id'],                    
                                'title'=>$row['title'],
                                'selling_price'=>$row['price'],
                                'quantity'=>$row['quantity'],
                                'item_total'=>$row['total']
                            ]
                    );
                }
            }   
            
            
            return response()->json([
                'success' => 1,
                'order_id' =>$order->id,
                'text' => 'Successfully saved',
            ], 200);
    
    
    
            
    payment success or response

    1. Once payment is completed, we should verify the payment

    2. new Api , the function 'fetch()' and razorpay_payment_id is used for verifying the payment

    3. the payment is success, we save the order into Order & OrderItems table

    
            public function paymentResponse(Request $request)
        {
            $razorpay_payment_id=$request->input('razorpay_payment_id');
            if(isset($razorpay_payment_id)){
                //whether already used or fake request
                $payment=OrderRequest::where('razorpay_payment_id',$razorpay_payment_id)->first();
                if(isset($payment)){
                    return response()->json([
                        'status' => 'error',
                        'message' =>'invalid payment.',
                        'code' => 'AUPI'
                    ], 500);
                }  
    
    
                try {
                    $api = new Api(env('RAZOR_KEY_ID'), env('RAZOR_KEY_SECRET'));            
                    $payment_details = $api->payment->fetch($razorpay_payment_id);
        
                    if($payment_details){
                        $response = $api->payment->fetch($razorpay_payment_id)->capture(array('amount'=>$payment_details->amount)); 
                    }
                }
                catch (exception $e) {
                    return response()->json([
                        'status' => 'error',
                        'message' =>'invalid payment.',
                        'code' => 'RAF'
                    ], 500);
                }
        
        
                try{
                    DB::beginTransaction(); 
                    $order_request=OrderRequest::where('id',$request->order_id)->where('created_by', Auth::id())->where('razorpay_payment_id',NULL)->first();
                    if(isset($order_request)){
                        $order_request->payment_status=$payment_details->status;;
                        $order_request->razorpay_payment_id=$razorpay_payment_id;
                        $order_request->payment_response=json_encode((array)$payment_details);
                        $order_request->save();
                    }
                    else{
                        DB::rollBack();
                        return response()->json([
                            'status' => 'error',
                            'message' =>'invalid payment.',
                            'code' => 'IPI'
                        ], 500); 
                    }
    
                    if($payment_details->status!="authorized"){
                        DB::rollBack();
                        return response()->json([
                            'status' => 'error',
                            'message' =>'invalid payment.',
                            'code' => 'RSF'
                        ], 500);
                    }
    
                    $address=Address::find($order_request->delivery_id);
                    //write code for order
                    
                    $orderData=$order_request->toArray();
                    $orderData['order_request_id']=$orderData['id'];
                    $orderData['delivery_name']=$address->firstname.' '.$address->lastname;
                    $orderData['delivery_address']=$address->address.', '.$address->city.', '.$address->state.', '.$address->country;
                    $orderData['delivery_zipcode']=$address->pin;
                    $orderData['delivery_landmark']=$address->landmark;
                    $orderData['delivery_mobile']=$address->mobile;
                    $orderData['delivery_email']=$address->email;
                    $orderData['order_status']='Pending';
                    $order=Order::create($orderData);
                    $this->data['order']=$order;
    
                  
    
                            $order_request_items=OrderRequestItems::where('order_request_id',$seller['id'])->get();
                            $this->data['orderDetails']=$order_request_items;
                            $order_request_items=$order_request_items->toArray();
                            if(isset($order_request_items)){
                                foreach($order_request_items as $item){
                                    $item['order_id']=$order->id;
                                    OrderItems::create($item);
                                }
                            }
    
    
                       
    
                    
    
                    DB::commit();  
                    $this->_sendEmailNotification();  
    
                } 
                catch(\Exception $e)
                {
                    return response()->json($e->getMessage());
                }
    
                return response()->json([
                    'status' => 'success',
                    'message' =>'Successfully placed your order.'
                ], 200);
    
    
            }
            else{
                return response()->json([
                    'status' => 'error',
                    'message' =>'invalid access.',
                    'code' => 'NRPI'
                ], 500);
            }
    
    
        }
    
        

    quantity increase and decrease feature

    
        $('body').on('click', '.cart_minus', function() {      
              var item_id=$(this).attr('data-id');         
              var cart_item=JSON.parse($.cookie("cart_item"));
              indexOfObject = cart_item.findIndex((obj => obj.item_id == item_id));         
             
              cart_item[indexOfObject].quantity = cart_item[indexOfObject].quantity-1;
              if(cart_item[indexOfObject].quantity<1){
                cart_item[indexOfObject].quantity=1;
              }
              cart_item[indexOfObject].total=cart_item[indexOfObject].quantity*cart_item[indexOfObject].price;
    
              $(this).parent().find('.cart-count').val(cart_item[indexOfObject].quantity);
              $.cookie("cart_item",JSON.stringify(cart_item),{ path: '/' });
              //$('.cart-item-main').empty();
              updateCartTotal(cart_item);
    
          });
    
          $('body').on('click', '.cart_plus', function() {      
    
              var item_id=$(this).attr('data-id');         
              var cart_item=JSON.parse($.cookie("cart_item"));
              indexOfObject = cart_item.findIndex((obj => obj.item_id == item_id));         
            
              cart_item[indexOfObject].quantity = cart_item[indexOfObject].quantity+1;
              cart_item[indexOfObject].total=cart_item[indexOfObject].quantity*cart_item[indexOfObject].price;
              $(this).parent().find('.cart-count').val(cart_item[indexOfObject].quantity);
              console.log(cart_item);
              $.cookie("cart_item",JSON.stringify(cart_item),{ path: '/' });
              //$('.cart-item-main').empty();          
              updateCartTotal(cart_item); 
    
        });